import base64
import json
import mimetypes
import sqlite3
import datetime

from flask import Flask
from flask_cors import CORS
from flask import request, jsonify
from sqlalchemy import desc

from model.models_1 import IPFS
from model.models_2 import Admin
from model.models_3 import Poison
from src.complieSolidity import get_info, search_poison
from static.extension import db
from model.models import User
import ipfs_api
import os
import jwt

from io import BytesIO
from flask import send_file

SECRET_KEY = '666-insecure-bu(cx7^^s0)6ut!-##8hg!k^1ln6wus=q2j^+ebm)j9e$%syoq'

basedir = os.path.abspath(os.path.dirname(__file__))

app = Flask(__name__)
CORS(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'users.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db.init_app(app)
# 设置文件上传目录
app.config['UPLOAD_FOLDER'] = 'uploads'
# 设置初始毒性和毒库
DEFAULT_NUM = 0
DEFAULT_TEXT = None


@app.cli.command()
def create():
    db.drop_all()
    db.create_all()
    User.init_db()


@app.route('/')
def hello_world():  # put application's code here
    return 'Welcome!'



# 用户数据id查询
@app.route('/users', methods=['GET'])
def get_users():
    # 用户数据查询
    user_id = request.args.get('id')  # 从请求参数中获取 id
    if user_id:
        user = User.query.get(int(user_id))  # 将 id 转换为整数并查询用户
        if user:
            return {
                'status': 'success',
                'message': '数据查询成功',
                'result': {
                    'id': user.id,
                    'username': user.username,
                    'password': user.password,
                }
            }
        else:
            return {
                       'status': 'fail',
                       'message': '未找到对应用户',
                   }, 404
    else:
        users = User.query.all()
        results = [
            {
                'id': user.id,
                'username': user.username,
                'password': user.password,
            } for user in users
        ]
        return {
            'status': 'success',
            'message': '数据查询成功',
            'results': results
        }

# 全体用户查询
@app.route('/users', methods=['GET'])
def Users_get( user_id=None):
    if not user_id:
        users = User.query.all()
        results = [
            {
                'id': user.id,
                'username': user.username,
                'password': user.password
            } for user in users
        ]
        return {
            'status': 'success',
            'message': '数据查询成功',
            'results': results
        }
    user = User.query.get(user_id)
    return {
        'status': 'success',
        'message': '数据查询成功',
        'result': {
            'id': user.id,
            'username': user.username,
            'password': user.password
        }
    }

# 用户注册
@app.route('/register/', methods=['POST'])
def post_user():
    # 用户注册逻辑
    data = request.json
    username = data.get('username')
    password = data.get('password')
    value = data.get('value')
    if value == '1':
        if not username or not password:
            return jsonify({'message': '用户名和密码不能为空'}), 500

        existing_user = User.query.filter_by(username=username).first()
        if existing_user:
            return jsonify({'message': '该用户名已被注册，请选择其他用户名'}), 409

        new_user = User(username=username, password=password)
        db.session.add(new_user)
        db.session.commit()

        return jsonify({
            'status': 200,
            'message': '用户注册成功'})

# 登录逻辑
@app.route('/login/', methods=['POST'])
def user_login():

    data = request.json
    username = data.get('username')
    password = data.get('password')
    value = int(data.get('value'))

    if value == 1:
        user = User.query.filter_by(username=username, password=password)
        if not username or not password:
            return jsonify({'message': '用户名和密码不能为空'}), 500

        elif user and user.first().password:
            dict = {
                "exp": datetime.datetime.now() + datetime.timedelta(days=1),  # 过期时间
                "iat": datetime.datetime.now(),  # 开始时间
                "id": user.first().id,
                "username": user.first().username,
            }
            token = jwt.encode(dict, SECRET_KEY, algorithm="HS256")
            return jsonify({
                'token': token,
                'username': username,
                'user_id': user.first().id,
                'isAdmin': 0,
                'status': 200,
                'message': '登录成功'
            })
        else:
            return jsonify({
                'status':500,
                'message': '用户名或密码错误'})
    else:
        user = Admin.query.filter_by(admin=username, password=password)
        if not username or not password:
            return jsonify({'message': '用户名和密码不能为空'}), 500

        elif user and user.first().password:
            dict = {
                "exp": datetime.datetime.now() + datetime.timedelta(days=1),  # 过期时间
                "iat": datetime.datetime.now(),  # 开始时间
                "id": user.first().id,
                "username": user.first().admin,
            }
            token = jwt.encode(dict, SECRET_KEY, algorithm="HS256")
            return jsonify({
                'token': token,
                'username': username,
                'user_id': user.first().id,
                'isAdmin': 1,
                'status': 200,
                'message': '登录成功'
            })
        else:
            return jsonify({
                'status': 500,
                'message': '用户名或密码错误'})



# 路由用于创建者接收文件上传
@app.route('/filePost/owner/', methods=['POST'])
def file_put_owner():
    # if 'file' not in request.files:
    #     return 'No file part'

    data = request.form
    print(f"Received form data: {data}")

    file = request.files.get('file')
    # 错误信息返回
    # 检查文件是否为空
    if file is None or file.filename == '':
        return jsonify({
            'code': 401,
            'message': '文件等数据读取错误，请重新登录',
        })

    # 正确信息返回
    if file:
        print(file, file.filename)
        filename = file.filename

    # 获取用户信息
    userid = data.get('userid')
    print(userid)
    username = data.get('username')
    print(username)

    # 用户自定义版本
    version = data.get('version')
    print(version)

    # CID上游存储
    up_CIDS = request.form.get('up_CIDS')
    print(up_CIDS)

    # 创建保存文件的文件夹
    upload_folder = app.config['UPLOAD_FOLDER']
    if not os.path.exists(upload_folder):
        os.makedirs(upload_folder)

    # 保存文件
    # 获取文件名和扩展名
    filename, ext = os.path.splitext(filename)

    # 构建带有用户ID后缀的文件名
    user_filename = f"{filename}_user{userid}_{version}{ext}"
    full_path = os.path.join(upload_folder, user_filename)


    # 构建文件保存路径
    file_path = os.path.join(upload_folder, user_filename)
    file.save(file_path)

    file_cid = get_CID(file_path)

    # 获取文件的毒信息,如果存在上游的话,可以进行更新
    existNum = DEFAULT_NUM
    poison = DEFAULT_TEXT

    # 版本号
    file_version = version

    # 检查CID是否存在
    check_result = check_CID(file_path,file_cid)
    # 检查返回值是否包含错误信息
    if check_result and check_result[1] == 404:
        return check_result[0]

    timestamp = get_time()
    project_code_base64 = create_project_code(userid,file)

    ipfs_set(project_code_base64, file_cid, file, userid, username, existNum, poison, file_version,
             timestamp,up_CIDS)

    CID_results = search_CID(up_CIDS)[0]
    all_poisons_str = search_CID(up_CIDS)[1]

    save_json_data(file_cid,file,CID_results,all_poisons_str,timestamp,file_version,username,user_filename,upload_folder,up_CIDS)


    # 上链！！！
    # 构造固定json返回格式
    returned_json = {
        'CID': file_cid,
        'name': file.filename,
        'upperstreamDependency': CID_results,
        'time': timestamp,
        'version': file_version,
        'user': username
    }
    # 将字典对象转换为 JSON 格式的字符串
    json_string = json.dumps(returned_json)

    # 调用函数
    upload_json_to_block(json_string)
    print("upload-success")

    # get-info的操作
    json_get_info(file_cid)
    print("info-success")

    # 搜索操作
    search_Poison_cid(file_cid)
    print("search-success")

    return jsonify({
        'message': '上传文件成功,并成功上链',
        'code': 200,
        'userid': userid,
        'username': username,
        'version': file_version,
        'up_CIDS': up_CIDS,
        'filename': filename,
    })


# 项目注册者上传文件，需要输入指定的项目码
@app.route('/filePost/contributor/', methods=['POST'])
def file_put_contributor():
    # 文件上传
    data = request.form
    print(f"Received form data: {data}")

    file = request.files.get('file')

    # 错误信息返回
    # 检查文件是否为空
    if file is None or file.filename == '':
        return jsonify({
            'code': 401,
            'message': '文件等数据读取错误，请重新登录',
        })

    if file:
        print(file, file.filename)
        filename = file.filename

    # 获取用户信息
    user_id = data.get('userid')
    print(user_id)
    user_name = data.get('username')
    print(user_name)

    # 用户自定义版本
    version = data.get('version')
    print(version)

    # 项目码
    user_projectCode = data.get('projectCode')
    print(user_projectCode)

    # CID上游存储
    up_CIDS = request.form.get('up_CIDS')
    print(up_CIDS)

    # 创建保存文件的文件夹
    upload_folder = app.config['UPLOAD_FOLDER']
    if not os.path.exists(upload_folder):
        os.makedirs(upload_folder)

    # 保存文件
    # 获取文件名和扩展名
    filename, ext = os.path.splitext(filename)

    # 构建带有用户ID,以及版本号的d后缀的文件名
    user_filename = f"{filename}_user{user_id}_{version}{ext}"
    full_path = os.path.join(upload_folder, user_filename)


    # 构建文件保存路径
    file_path = os.path.join(upload_folder, user_filename)
    file.save(file_path)

    file_cid = get_CID(file_path)

    # 获取毒信息
    # 获取文件的毒信息,用户使用的时候上传文件默认是无毒
    existNum = DEFAULT_NUM
    poison = DEFAULT_TEXT

    # 版本号
    file_version = version


    check_result = check_CID(file_path, file_cid)
    # 检查CID是否存在
    if check_result and check_result[1] == 404:
        return check_result[0]

    # 校验项目码
    check_PC = check_pojectCode(file_path,user_projectCode,up_CIDS)
    if check_PC and check_PC[1] == 404:
        return check_PC[0]
    # 返回毒状态码和毒元素
    if check_PC and check_PC[1] !=404:
        existNum = check_PC[0]
        poison = check_PC[1]

    # 校验文件CID
    check_CID(file_path, file_cid)

    # 时间戳
    timestamp = get_time()

    # 项目码
    project_code_base64 = user_projectCode

    ipfs_set(project_code_base64, file_cid, file, user_id, user_name, existNum, poison, file_version,
             timestamp, up_CIDS)

    CID_results = search_CID(up_CIDS)[0]
    all_poisons_str = search_CID(up_CIDS)[1]

    save_json_data(file_cid, file, CID_results, all_poisons_str, timestamp, file_version, user_name,
                   user_filename, upload_folder, up_CIDS)


    # 构造固定json返回格式
    returned_json = {
        'CID': file_cid,
        'name': file.filename,
        'upperstreamDependency': CID_results,
        'time': timestamp,
        'version': file_version,
        'user': user_name
    }
    # 将字典对象转换为 JSON 格式的字符串
    json_string = json.dumps(returned_json)

    # 调用函数
    upload_json_to_block(json_string)
    print("upload-success")

    # get-info的操作
    json_get_info(file_cid)
    print("info-success")

    # 搜索操作
    search_Poison_cid(file_cid)
    print("search-success")


    # 按要求返回路径
    return jsonify({
        'message': '上传文件成功，并成功上链',
        'code': 200,
        'userid': user_id,
        'username': user_name,
        'version': file_version,
        'up_CIDS':up_CIDS,
        'filename':filename,
        'projectCode':user_projectCode,
    })


# 返回用户id为主键的全部信息
@app.route('/search_own/', methods=['GET'])
def search_own():
    userid = request.args.get('userid')

    # 查询用户上传的文件信息
    user_files = IPFS.query.filter_by(userid=userid).all()

    # 计算总数
    total_num = len(user_files)

    # 分页逻辑
    page = request.args.get('pageNum', default=1, type=int)
    page_size = request.args.get('pageSize', default=10, type=int)
    start = (page - 1) * page_size
    end = start + page_size
    user_files_paginated = user_files[start:end]

    # 构建返回的数据结构
    files_data = []
    for file in user_files_paginated:

        poison_info = file.poison if file.poison else "暂时未发现"
        exist_value = "是" if file.poisonExist == 1 else "否"
        Exist_upcids = file.upCIDS if file.upCIDS else "无"
        file_info = {
            'projectCode': file.projectCode,
            'filename': file.filename,
            'CID': file.CID,
            'timestamp': file.timestamp,
            'version': file.version,
            'upCIDS': Exist_upcids,
            'poisonExist': exist_value,
            'poisonUp': check_poison_origin(file.poison),  # 毒源支持最近一级的
            'poison': poison_info,
        }
        files_data.append(file_info)

    # 构建返回数据
    data = {'code': 200, 'message': "已获取登录用户全部项目信息",'zs': total_num, 'data': files_data}
    return jsonify(data)


# 用户搜索文件名、和用户id进行绑定
@app.route('/search_file/', methods=['GET'])
def search_file():
    userid = request.args.get('userid')
    filename = request.args.get('name')  # 从请求参数中获取文件名

    # 从数据库中查询用户上传的指定文件信息
    search_files = IPFS.query.filter_by(userid=userid,filename=filename ).all()


    # 分页逻辑
    page = request.args.get('pageNum', default=1, type=int)
    page_size = request.args.get('pageSize', default=10, type=int)
    start = (page - 1) * page_size
    end = start + page_size
    search_files_paginated = search_files[start:end]

    # 计算总数
    total_num = len(search_files_paginated)

    # 构建返回的数据结构
    files_data = []
    for file in search_files_paginated:
        poison_value = file.poison if file.poison else "暂时未发现"
        exist_value = "是" if file.poisonExist == 1 else "否"
        Exist_upcids = file.upCIDS if file.upCIDS else "无"
        file_info = {
            'userid': file.userid,
            'projectCode': file.projectCode,
            'filename': file.filename,
            'CID': file.CID,
            'timestamp': file.timestamp,
            'version': file.version,
            'upCIDS': Exist_upcids,
            'poisonExist': exist_value,
            'poisonUp': check_poison_origin(file.poison),  # 毒源支持最近一级的
            'poison': poison_value,
        }
        files_data.append(file_info)

    # 构建返回数据
    data = {'code': 200, 'message': "已获取搜索项目文件全部信息",'zs': total_num, 'data': files_data}
    return jsonify(data)


# 用户仅搜索文件名
@app.route('/search_file_name/', methods=['GET'])
def search_file_name():
    filename = request.args.get('name')  # 从请求参数中获取文件名

    # 从数据库中查询用户上传的指定文件信息
    search_files = IPFS.query.filter_by(filename=filename).all()


    # 分页逻辑
    page = request.args.get('pageNum', default=1, type=int)
    page_size = request.args.get('pageSize', default=10, type=int)
    start = (page - 1) * page_size
    end = start + page_size
    search_files_paginated = search_files[start:end]

    # 计算总数
    total_num = len(search_files_paginated)

    # 构建返回的数据结构
    files_data = []
    for file in search_files_paginated:
        poison_value = file.poison if file.poison else "暂时未发现"
        exist_value = "是" if file.poisonExist == 1 else "否"
        Exist_upcids = file.upCIDS if file.upCIDS else "无"
        file_info = {
            'userid': file.userid,
            'projectCode': file.projectCode,
            'filename': file.filename,
            'CID': file.CID,
            'timestamp': file.timestamp,
            'version': file.version,
            'upCIDS': Exist_upcids,
            'poisonExist': exist_value,
            'poisonUp': check_poison_origin(file.poison),  # 毒源支持最近一级的
            'poison': poison_value,
        }
        files_data.append(file_info)

    # 构建返回数据
    data = {'code': 200, 'message': "已获取搜索项目文件全部信息",'zs': total_num, 'data': files_data}
    return jsonify(data)


# 得到全体组件的毒信息
@app.route('/getAll/', methods=['GET'])
def get_ALL():
    # 查询用户上传的文件信息
    files = IPFS.query.order_by(IPFS.filename, IPFS.version).all()


    # 分页逻辑
    page = request.args.get('pageNum', default=1, type=int)
    page_size = request.args.get('pageSize', default=10, type=int)
    start = (page - 1) * page_size
    end = start + page_size
    files_paginated = files[start:end]

    # 计算总数
    total_num = len(files)

    # 构建返回的数据结构
    files_data = []
    for file in files_paginated:
        update_ipfs_poison(file.CID)
        poison_value = file.poison if file.poison else "暂时未发现"
        exist_value = "是" if file.poisonExist == 1 else "否"
        Exist_upcids = file.upCIDS if file.upCIDS else "无"
        file_info = {
            'filename': file.filename,
            'CID': file.CID,
            'timestamp': file.timestamp,
            'version': file.version,
            'Username': file.username,
        }
        files_data.append(file_info)

    # 构建返回数据
    data = {'code': 200, 'message': "已获取全部项目信息", 'zs': total_num, 'data': files_data}
    return jsonify(data), 200


# 具体行组件的以filename区分的毒信息
@app.route('/getOne/', methods=['GET'])
def get_One():
    # 参数返回的是当前的行name信息和时间戳
    filename = request.args.get("name")
    CID = request.args.get("CID")


    # 根据 filename 查询对应的文件信息
    file = IPFS.query.filter_by(filename=filename,CID=CID).first()

    # 如果找不到对应的文件，则返回空数据
    if not file:
        return jsonify({'code': 404, 'message': "未找到该文件"}), 404

    # 构建返回的数据结构
    poison_value = file.poison if file.poison else "暂时未发现"
    exist_value = "是" if file.poisonExist == 1 else "否"
    file_info = {
        'name': file.filename,
        'up_CIDS': file.upCIDS,
        'Exist': exist_value,
        'up': check_poison_origin(file.poison),
        'poison': poison_value
    }

    # 更新CID的上游毒库和毒性,第一次修改状态码，第二次修改毒性
    update_ipfs_poison(file.CID)
    update_ipfs_poison(file.CID)

    # 获取CIDS格式
    CID_results = search_CID(file.upCIDS)[0]
    print(CID_results)


    # 上链！！！
    # 构造固定json返回格式

    returned_json = {
        'CID': file.CID,
        'name': file.filename,
        'upperstreamDependency': CID_results,
        'time': file.timestamp,
        'version': file.version,
        'user': file.username
    }
    # 将字典对象转换为 JSON 格式的字符串
    json_string = json.dumps(returned_json)

    # 调用函数
    upload_json_to_block(json_string)
    print("upload-success")

    # get-info的操作
    json_get_info(file.CID)
    print("info-success")

    # 搜索操作
    search_Poison_cid(file.CID)
    print("search-success")


    # 构建返回数据
    data = {'code': 200, 'message': "详情页已展开,实时更新毒",  'data': [file_info]}
    return jsonify(data), 200


# 用户点击下载进行处理，获取唯一CID从数据库指定路径进行下载：
@app.route('/download/')
def download_file():
    # 从请求参数中获取 CID
    cid = request.args.get('cid')
    if cid:
        file = IPFS.query.filter_by(CID=cid).first()
        if file:
            filename = file.filename

            if file.poisonExist == 1:
                return jsonify({"message": "文件有毒，禁止下载", 'code': 403})

            version = file.version
            userid = file.userid
            # 从文件名中提取出真正的文件名
            true_filename, file_extension = os.path.splitext(filename)

            # 构建文件路径
            file_path = f"uploads/{true_filename}_user{userid}_{version}{file_extension}"
            try:
                # 设置文件的 MIME 类型
                mimetype = mimetypes.guess_type(file_path)[0]
                # 读取文件内容
                with open(file_path, 'rb') as f:
                    file_content = BytesIO(f.read())
                # 设置响应的Content-Disposition头部，让浏览器下载文件
                return send_file(file_content, as_attachment=True, mimetype=mimetype, download_name=true_filename)

            except FileNotFoundError:
                return jsonify({"message":"文件未找到", 'code':404})
        else:
            return jsonify({"message":"文件并未存储", 'code':405})
    else:
        return jsonify({"message": "文件丢失", 'code': 400})


# 注册CID对应的毒信息
@app.route('/admin/poison/set/', methods=['POST'])
def register_poison():

    data = request.form
    CID = data.get('CID')
    print(CID)
    poison_exist = 1
    new_poison = data.get('new_poison')

    # 在用户下载的时候进行更新
    # update_ipfs_poison(CID, poison_exist, new_poison)
    # 更新老版本文件：
    conn = sqlite3.connect('users.sqlite')
    cursor = conn.cursor()
    cursor.execute("UPDATE IPFS SET poisonExist = ?, poison = ? WHERE CID = ?",
                   (poison_exist, new_poison, CID))

    # 提交更改

    conn.commit()
    print("老版本毒信息已成功更新到IPFS表和Poison表中")


    poison_entry = Poison()
    poison_entry.CID = CID
    poison_entry.poison = new_poison
    # 将 poison 对象添加到数据库会话中,并提交更改. 绑定CID和poison
    db.session.add(poison_entry)
    db.session.commit()

    # 获取有毒版本的项目码
    # update_all_ipfs_poison(CID,new_poison)

    return jsonify({
        'message':'毒更新成功！',
        'code':200,
        'CID':CID,
        'poisonExist':poison_exist,
        'new_poison':new_poison
    })


# 用户下载的时候，点操作详情，我们根据当前文件的CID去查它的upCIDS，upCIDS中的元素是否在毒表中，如果存在的话，那么数据库修改为有毒标志位poisonExist，并且把毒写入poison中；
# 最好再重新将CID这条数据进行上链；
# 下载更新数据库
def update_ipfs_poison(cid):

    try:
        # 连接到数据库
        conn = sqlite3.connect('users.sqlite')
        cursor = conn.cursor()

        # 查询指定 CID 的上游 CIDS
        cursor.execute("SELECT upCIDS, poison FROM IPFS WHERE CID = ?", (cid,))
        row = cursor.fetchone()
        up_cids = row[0]
        print(up_cids)
        poison_Num = row[1]
        # 默认无毒
        real_poisonExist = 0

        if up_cids:
            # 分割上游 CIDS
            up_cids_list = up_cids.split(',')

            updated_poison_list = []  # 用于累积所有查询得到的 poison
            print(up_cids_list)
            for up_cid in up_cids_list:
                # 查询上游 CID 在毒表中的毒信息
                print(up_cid)
                cursor.execute("SELECT poison FROM poison WHERE CID = ?", (up_cid,))
                row = cursor.fetchone()
                # 检查是否找到了符合条件的记录
                if row is not None:
                    # 对应溯源更新一级上游的毒
                    cursor.execute("UPDATE IPFS SET poisonExist = ?, poison = ? WHERE CID = ?",
                                   (1, row[0], cid))
                    real_poisonExist = 1
                    existing_poison = row[0]
                    print(row[0])

                    # 如果现有毒字段不为空，则添加到累积列表中
                    if existing_poison:
                        updated_poison_list.append(existing_poison)

            # 使用逗号拼接所有毒信息
            updated_poison = ','.join(updated_poison_list)
            print(updated_poison)

            if poison_Num:
                real_poison = "," + updated_poison
            else:
                real_poison = updated_poison

            # 更新当前 CID 的毒信息和毒存在标记
            cursor.execute("UPDATE IPFS SET poisonExist = ?, poison = ? WHERE CID = ?",
                                       (real_poisonExist, real_poison, cid))

        # 提交更改
        conn.commit()
        print("毒信息已成功更新到IPFS表和Poison表中")

    except sqlite3.Error as e:
        print("发生错误：", e)
    finally:
        # 关闭数据库连接
        if conn:
            conn.close()



# 下面是调用函数

# 检查一级毒源
def check_poison_origin(poison):
    if poison is None or poison.strip() == '':  # 如果 poison 为 None 或者为空字符串
        return "暂时未发现"

    # 以逗号为分隔符拆分 poison
    poisons = poison.split(', ')
    cids = []
    conn = sqlite3.connect('users.sqlite')
    cursor = conn.cursor()

    # 查询数据库，找到每个 poison 对应的 CID
    for poi in poisons:
        cursor.execute("SELECT upCIDS FROM IPFS WHERE poison = ?", (poi,))
        result = cursor.fetchone()
        if result and result[0]:  # 判断查询结果不为空且 CID 不为空
            cids.append(str(result[0]))

    conn.close()

    if len(cids) == 1:
        return cids[0]
    else:
        return ','.join(cids)  # 将 CID 列表转换为逗号分隔的字符串并返回



# 获取CID
def get_CID(file_path):
    file_cid = ipfs_api.publish(file_path)
    return file_cid

# 获取版本号，用户自行输入
# def get_version(upload_folder,user_filename,file_path,count):
#     # 版本号
#     file_version = get_file_version(upload_folder, user_filename)
#
#     return file_version

# 获取项目码同时判断是否有毒
def check_pojectCode(file_path,user_projectCode,up_CIDS):

    # 比较用户输入的项目码和注册的项目码
    if user_projectCode is None:
        os.remove(file_path)  # 删除刚刚保存的文件
        response = jsonify({
            'code': 500,
            'message': '用户无法进行修改，需要获取创建该项目的项目码',
            },)
        return response,404

    # 如果项目码正确，检查是否存在毒
    poison_Exist, poison = check_poison_exist(up_CIDS)
    return poison_Exist, poison


# 检查项目是否存在毒
def check_poison_exist(up_CIDS):
    ppoison_exist = 0

    conn = sqlite3.connect('users.sqlite')
    cursor = conn.cursor()

    # 初始化一个集合，用于保存一级上游含有的所有毒元素
    all_poisons = set()

    for cid in up_CIDS:
        # 执行查询语句，查找与给定 CID 相关的毒属性及状态码
        cursor.execute("SELECT poisonExist, poison FROM IPFS WHERE CID = ?", (cid,))
        result = cursor.fetchone()  # 获取第一条结果

        if result:
            poison_exist, poison = result
            # 如果查找到毒存在且状态码为1，则更新对应的毒属性
            if poison_exist == 1:
                ppoison_exist = result[0]
                all_poisons.add(poison)

        conn.close()
        # 将集合转换为逗号分隔的字符串形式
        poisons_str = ','.join(all_poisons) if all_poisons else ''

        return ppoison_exist, poisons_str
    else:
        conn.close()
        return 0, None  # 如果没有毒存在，则返回0和None

# 查询数据库中是否存在相同CID的文件
def check_CID(file_path, file_cid):

    conn = sqlite3.connect('users.sqlite')
    cursor = conn.cursor()
    existing_file = cursor.execute("SELECT * FROM IPFS WHERE CID = ?", (file_cid,)).fetchone()

    # 如果存在相同CID的文件，则返回错误信息,只有可能在创建项目时候,因为后续都需要使用相同的项目码进行测试
    if existing_file:
        os.remove(file_path)  # 删除刚刚保存的文件

        response = jsonify({
            'code': 400,
            'message': '相同CID的文件已经存在！'
        })
        return response, 404


def get_time():
    # 获取当前的时间戳
    current_time = datetime.datetime.now()

    # 将时间格式化为 ISO 8601 格式, 保存时间戳
    iso_format = current_time.strftime("%Y-%m-%dT%H:%M:%S")
    timestamp = str(iso_format)
    return timestamp

# 创建项目码
def create_project_code(user_id, uploaded_file):
    project_code_simple = f"{user_id}_{uploaded_file.filename}"  # 生成项目码
    # 将 project_code 转换为 bytes 对象
    project_code_bytes = project_code_simple.encode('utf-8')

    # 对 bytes 对象进行 Base64 编码
    project_code_base64 = base64.urlsafe_b64encode(project_code_bytes).decode('utf-8')

    return project_code_base64


def ipfs_set(project_code_base64, file_cid, uploaded_file, user_id, user_name, existnum, poison, file_version, timestamp, up_CIDS):
    # 创建 IPFS 对象并设置字段值
    ipfs_entry = IPFS()
    ipfs_entry.projectCode = project_code_base64
    ipfs_entry.CID = file_cid
    ipfs_entry.filename = uploaded_file.filename
    ipfs_entry.userid = user_id
    ipfs_entry.username = user_name
    ipfs_entry.version = file_version
    ipfs_entry.upCIDS = up_CIDS
    ipfs_entry.poisonExist = existnum
    ipfs_entry.poison = poison
    ipfs_entry.version = file_version
    ipfs_entry.timestamp = timestamp
    # 将 IPFS 对象添加到数据库会话中并提交更改
    db.session.add(ipfs_entry)
    db.session.commit()

def search_CID(up_CIDS):
    # 查询同名文件的CID情况
    CID_results, all_poisons_str = get_cid_from_database(up_CIDS)
    return CID_results, all_poisons_str


# 保存json文件
def save_json_data(file_cid,uploaded_file,CID_results,all_poisons_str,timestamp,file_version,user_name,user_filename,upload_folder,up_CIDS):
    json_data = {
        'CID': file_cid,
        'name': uploaded_file.filename,
        'up_CIDS': up_CIDS,
        'upperstreamDependency': CID_results,
        'poison': all_poisons_str,
        'time': timestamp,
        'version': file_version,
        'user': user_name
    }

    json_user_name = user_filename.rsplit('.', 1)[0]
    json_file_name = f'file_info_{json_user_name}.json'
    json_file_path = os.path.join(upload_folder, json_file_name)

    # 将Unicode转义序列转换成中文字符
    json_data['name'].encode('utf-8').decode('unicode_escape')
    json_data['user'].encode('utf-8').decode('unicode_escape')

    # 将转换后的数据保存为 JSON 文件
    with open(json_file_path, 'w', encoding='utf-8') as f:
        json.dump(json_data, f, ensure_ascii=False, indent=4)



    # 上传文件到IPFS
def upload_file(file_path: str):
    file_cid = ipfs_api.publish(file_path)
    return file_cid

    # 下载文件到本地
def download_file(file_cid: str, path: str):
    ipfs_api.download(file_cid, path)


# 从IPFS中获取同名文件的CID和poison
def get_cid_from_database(up_CIDS):
    # 连接到 SQLite 数据库
    conn = sqlite3.connect('users.sqlite')
    cursor = conn.cursor()

    # 将查询结果转换为字典格式
    formatted_results = []

    # 初始化一个集合，用于保存不同种类的poison
    poison_types = set()

    # 按逗号分割 up_CIDS
    cids_list = up_CIDS.split(',')

    # 遍历 up_CIDS 中的每个 CID
    for cid in cids_list:
        # 执行查询语句，获取给定文件名和 CID 对应的毒属性
        cursor.execute("SELECT DISTINCT poison FROM IPFS WHERE CID = ?", (cid,))
        result = cursor.fetchall()

        # 提取毒属性并添加到 poison_types 集合中
        for row in result:
            poison = row[0]

            if poison is None:
                poison = 'NULL' # 将 None 转换为一个空的字符串数组
            formatted_results.append({'CID': cid, 'poison': poison})
            if poison:
                poison_types.add(poison)

    # 关闭数据库连接
    conn.close()

    all_poisons_str = ', '.join(poison_types)
    input_list = all_poisons_str.split(',')
    cleaned_data = [item.strip().replace(' ', '') for item in input_list]
    unique_list = list(set(cleaned_data))
    output_str = ','.join(unique_list)

    return formatted_results, output_str



def get_poison_2(CID):
    # 连接到 SQLite 数据库
    conn = sqlite3.connect('users.sqlite')
    cursor = conn.cursor()

    # 执行查询语句
    cursor.execute("SELECT poisonExist, poison FROM IPFS WHERE CID = ?", (CID,))
    results = cursor.fetchall()
    print(results)

    conn.close()
    # 关闭数据库连接
    return results

# user_api = UserApi.as_view('user_api')
# app.add_url_rule('/register', view_func=user_api, methods=['POST',])
# app.add_url_rule('/login', view_func=user_api, methods=['PUT',])
# app.add_url_rule('/users', view_func=user_api, methods=['GET',])


# 解析用户修改时候的返回数据，将信息上传到区块链中
def upload_json_to_block(returned_json):
    # 解析返回的JSON数据
    data = json.loads(returned_json)
    upperstreamDependency = data['upperstreamDependency']

    # 从原JSON数据中获取需要的字段
    CID = data['CID']
    name = data['name']
    time = data['time']
    version = data['version']
    user = data['user']

    # 分别存储 CID 和 poison 的列表
    depCIDs = []
    depPoisons = []

    # 遍历 upperstreamDependency 列表
    for dependency in upperstreamDependency:
        # 将 CID 和 poison 分别存储到对应的列表中
        depCIDs.append(dependency.get('CID', ''))
        depPoisons.append(dependency.get('poison', ''))

    # print(CID)
    # print(name)
    # print(depCIDs)
    # print(depPoisons)
    # print(time)
    # print(str(version))
    # print(user)

    # # 调用upload函数
    from src.complieSolidity import upload
    receipt = upload(CID, name, list(depCIDs),list(depPoisons), time, str(version), user)
    print(f"Upload Receipt: {receipt}")

# get-info信息
def json_get_info(CID):
    info = get_info(CID)
    print(info)

# 搜索Poison位置
def search_Poison_cid(CID):
    s = search_poison(CID)
    print(s)


if __name__ == "__main__":
    app.run(debug=True)
